#include <iostream>
using namespace std;
/*
提高cin、cout效率：
    ios::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);
*/
/************** 单链表 *************/
// const int N = 1e5 + 10;
// int e[N], ne[N], h, idx;
// void init()
// {
//     h = -1;
// }
// void pushH(int x)
// {
//     e[idx] = x, ne[idx] = h, h = idx++;
// }
// void pushK(int k, int x)
// {
//     e[idx] = x, ne[idx] = ne[k], ne[k] = idx++;
// }
// void remove(int k)
// {
//     ne[k] = ne[ne[k]];
// }
// int main()
// {
//     init();
//     int m;
//     scanf("%d", &m);
//     char op;
//     int k, x;
//     while (m--)
//     {
//         scanf(" %c", &op);
//         if (op == 'H')
//         {
//             scanf("%d", &x);
//             pushH(x);
//         }
//         else if (op == 'D')
//         {
//             scanf("%d", &k);
//             if(k == 0)
//             {
//                 //remove(h);
//                 h = ne[h];
//             }
//             else
//                 remove(k - 1);
//         }
//         else
//         {
//             scanf("%d %d", &k, &x);
//             pushK(k - 1, x);
//         }
//     }
//     for (int i = h; i != -1; i = ne[i])
//         printf("%d ", e[i]);
//     return 0;
// }

/****************** 双链表 ******************/
/*
const int N = 1e5 + 10;
int e[N], r[N], l[N], idx, h, t;
void init()
{
    idx = 2;
    r[0] = 1;
    l[1] = 0;
    h = 0, t = 1;
}
void push(int k, int x)
{
    e[idx] = x;
    r[idx] = r[k];
    l[idx] = k;
    l[r[k]] = idx;
    r[k] = idx++;
}
void remove(int k)
{
    r[l[k]] = r[k];
    l[r[k]] = l[k];
}
int main()
{
    init();
    int m;
    scanf("%d", &m);
    char op[3]; // char op[2]; 会出bug，导致m异常
    int x, k;
    while(m--)
    {
        scanf("%s", op);
        if(op[0] == 'L')
        {
            scanf("%d", &x);
            push(h, x);
        }
        else if(op[0] == 'R')
        {
            scanf("%d", &x);
            push(l[t], x);
        }
        else if(op[0] == 'D')
        {
            scanf("%d", &k);
            remove(k + 1);
        }
        else
        {
            scanf("%d%d", &k, &x);
            if (op[1] == 'L') push(l[k + 1], x);
            else    push(k + 1, x);
        }
        puts("");
        for (int i = r[h]; i != t; i = r[i])
        {
            printf("%d ", e[i]);
        }
        puts("");
    }
    // for(int i = r[h]; i != t; i = r[i])
    // {
    //     printf("%d ", e[i]);
    // }
    return 0;
}*/

/****************  模拟栈 *****************/
/*
const int N = 1e5 + 10;
int st[N], top;
int main()
{
    int m;
    cin >> m;
    string op;
    int x;
    while(m--)
    {
        cin >> op;
        if(op == "push")
        {
            cin >> x;
            st[top++] = x;
        }
        else if(op == "pop")
            top--;
        else if(op == "empty")
        {
            if(top == 0)    puts("YES");
            else    puts("NO");
        }
        else
            cout << st[top - 1] << endl;
    }
    return 0;
}*/

/************ 模拟队列 ************/
/*
const int N = 1e5 + 10;
int q[N], front, rear;
int main()
{
    int m;
    cin >> m;
    string op;
    int x;
    while (m--)
    {
        cin >> op;
        if (op == "push")
        {
            cin >> x;
            q[rear++] = x;
        }
        else if (op == "pop")
            front++;
        else if (op == "empty")
        {
            if (front == rear)
                puts("YES");
            else
                puts("NO");
        }
        else
            cout << q[front] << endl;
    }
    return 0;
}*/

/*********** 单调栈 ***********/
// 给定一个长度为 N的整数数列，输出每个数左边第一个比它小的数，如果不存在则输出 −1。
// a1  a2  a3 ... ai
// 找ai左侧的首个小于ai的。如果 a2 > a3, 那永远不会选到a2
/*
const int N = 1e5 + 10;
int arr[N], st[N], top;

int main()
{
    int n;
    scanf("%d", &n);
    for (int i = 0; i < n; ++i)
    {
        scanf("%d", arr + i);
        //栈顶>=，就一直出栈
        while (top && st[top - 1] >= arr[i])
            --top;
        if (top == 0)
            printf("-1 ");
        else
            printf("%d ", st[top - 1]);
        st[top++] = arr[i];
    }
    return 0;
}*/

/********** 单调队列 **********/
// 滑动窗口最小值。窗口长度位k
/*
const int N = 1e6 + 10;
int arr[N];
int q[N], h, t;
int main()
{
    int n, k;
    scanf("%d%d", &n, &k);
    //找最小值
    for (int i = 0; i < n; ++i)
    {
        scanf("%d", arr + i);
        //判断队头是否要出队
        if(i - q[h] + 1 > k) ++h;
        //来了个比队尾更小的，队尾直接被优化掉
        while(h != t && arr[q[t - 1]] >= arr[i]) --t;
        q[t++] = i;
        //能构成一个窗口，才输出
        if(i >= k - 1) printf("%d ", arr[q[h]]);
    }
    puts("");

    //找最大值
    h = t = 0;
    for (int i = 0; i < n; ++i)
    {
        if(i - q[h] + 1 > k) ++h;
        while(h != t && arr[q[t - 1]] <= arr[i]) --t;
        q[t++] = i;
        if(i >= k - 1) printf("%d ", arr[q[h]]);
    }
    return 0;
}*/

/************** KMP ***************/
/*暴力做法
    for(int i = 0; i < n; ++i)
    {
        int j = 0, k = i;
        for(; j < m; ++j)
        {
            if(s[k] != p[j])
                break;
            ++k;
        }
        if(j == m)
            printf("%d ", i);
    }
*/
const int M = 1e5 + 10;
const int N = 1e6 + 10;
char p[M], s[N];
int ne[M];
// 规定一下：s为字符串，p为模式串。
// ne[j] 表示 j 最少回退到 ne[j]位置，使得p[1, ne[j]] == p[, j].
// p[j]前面的都匹配，但 s[i] != p[j + 1]，那模式串p就要往后移，
// 我们想知道最少往后移动到哪里才可能继续匹配 => 求最长的前缀 p[1, x] == p[, j] 且 (x != j), 这样 s[i]才可能等于p[j + 1]
int main()
{
    int m, n;
    cin >> m >> p + 1 >> n >> s + 1;
    // 求next数组
    // 从2开始，ne[1]默认是0。j可以认为是 p[i - 1]回退的位置 p[1, j] == p[, i-1]
    for (int i = 2, j = 0; i <= m; ++i)
    {
        // 不匹配，往前移。j==0时，表示退无可退了
        while (j && p[i] != p[j + 1])
            j = ne[j];
        // 相等了，更新j
        if (p[i] == p[j + 1])
            ++j;
        ne[i] = j;
    }

    for (int i = 1, j = 0; i <= n; ++i)
    {
        while (j && s[i] != p[j + 1])
            j = ne[j];
        if (s[i] == p[j + 1])
            ++j;
        if (j == m)
        {
            cout << i - j << " "; // 这里题目说下标从0开始。原本应该是i-j+1, 我们字符串都从1开始所以要再-1
            j = ne[j];            // 这一步可以不写。但还是写一下比较好
        }
    }
    return 0;
}